/**
 * 删除动作
 */
function sDeleteAction(type){
    var _type = type;

    /**
     * 删除元素集合
     */
    var elements = [];

    /**
     * 选择区域
     */
    var selection_ranges = {};

    /**
     * 动作发生所在偏移量
     */
    var _offset = null;

    /**
     * 动作发生时的选项
     */
    var _opt = null;

    /**
     * 留痕状态
     */
    var _leaveTrace = false;

    /**
     * 获取动作类型
     */
    this.getActType = function(){
        return ssDict.sActionType.DELETE;
    }

    /**
     * 获取区域类型
     * @returns 
     */
    this.getType = function(){
        return _type;
    }

    /**
     * 设置留痕状态
     * @param {*} status true留痕 false不留痕
     */
    this.setLeaveTrace = function(status){
        _leaveTrace = status;
    }

    /**
     * 设置选择区域
     * @param {*} selectionRange 选择范围对象
     * @param {*} before 动作之前
     */
    this.setSelectionRange = function(selectionRange, before){
        selection_range = {
            startOffset: null,
            endOffset: null,
            __position: selectionRange.__position
        };

        selection_range.startOffset = this.deepCloneOffset(selectionRange.startOffset);
        selection_range.endOffset = this.deepCloneOffset(selectionRange.endOffset);

        selection_ranges[before ? "reverse" : "recover"] = selection_range;
    }

    /**
     * 设置动作发生时偏移量
     * @param {*} offset 
     * @param {*} opt 
     */
    this.setOffset = function(offset, opt) {
        _offset = offset;
        _opt = opt;
    }

    /**
     * 获取第一个指定类型的元素
     * @param {*} type 
     * @returns 
     */
    this.getFirstElement = function(type){
        for(var i in elements){
            if(elements[i].element._sType == type){
                return elements[i];
            }
        }
        return !type && elements.length > 0 ? elements[0] : null;
    }

    /**
     * 获取最后一个指定类型的元素
     * @param {*} type 
     * @returns 
     */
    this.getLastElement = function(type){
        for(var i = elements.length - 1; i >= 0; i--){
            if(elements[i].element._sType == type){
                return elements[i];
            }
        }
        return elements.length > 0 ? elements[elements.length - 1] : null;
    }

    /**
     * 添加元素
     * @param {*} element 元素
     * @param {*} offset 元素偏移量
     * @param {*} mutate 标记是否变异
     * @param {*} opt 可选项
     */
    this.add = function(element, offset, mutate, opt){
        if(element._sType == "sText"){
            this.addText(element, offset, mutate, opt);
        }else if(element._sType == "sLayer"){
            this.addLayer(element, offset, mutate, opt);
        }else if(element._sType == "sParagraph"){
            this.addParagraph(element, offset, opt);
        }
    }

    /**
     * 添加文本元素
     * @param {*} element 元素
     * @param {*} offset 元素偏移量
     * @param {*} mutate 标记是否变异
     * @param {*} opt 可选项
     */
    this.addText = function(element, offset, mutate, opt){
        opt = opt ? opt : {};
        
        offset = this.deepCloneOffset(offset);

        offset.range = !offset.range 
        ? {
            start: element.innerText.length - 1,
            end: element.innerText.length
            }
        : offset.range

        var el = {
            element: element,
            offset: offset,
            oldParagraphIndex: element.__paragraphIndex
        };
        
        if(opt.mutateNew){
            el.mutateNew = true;
        }else if(mutate){
            el.mutate = true;
        }

        if(opt.prepend){
            elements.splice(0, 0, el);
        }else{
            elements.push(el);
        }

        return this;
    }

    /**
     * 添加层元素
     * @param {*} element 元素
     * @param {*} offset 元素偏移量
     * @param {*} mutate 标记是否变异
     * @param {*} opt 可选项
     */
    this.addLayer = function(element, offset, mutate, opt){
        opt = opt ? opt : {};

        offset = this.deepCloneOffset(offset);

        offset.range = !offset.range 
        ? {
            start: -1,
            end: 0
        }
        : offset.range

        var el = {
            element: element,
            offset: offset,
            mutate: mutate,
            oldParagraphIndex: element.__paragraphIndex
        };

        if(opt.prepend){
            elements.splice(0, 0, el);
        }else{
            elements.push(el);
        }

        return this;
    }

    /**
     * 加入段落
     * @param {*} element 段落元素
     * @param {*} offset 元素偏移量
     * @param {*} opt 可选项
     */
    this.addParagraph = function(element, offset, opt){
        opt = opt ? opt : {};

        var el = {
            element: element,
            offset: this.deepCloneOffset(offset)
        };

        if(opt.prepend){
            elements.splice(0, 0, el);
        }else{
            elements.push(el);
        }
    }

    /**
     * 变异段落
     * @param {*} element 段落元素
     * @param {*} offset 元素偏移量
     */
    this.mutateParagraph = function(element, offset, opt){
        opt = opt ? opt : {};

        var el = {
            element: element,
            offset: this.deepCloneOffset(offset),
            mutate: true
        };

        if(opt.style){
            el.oldStyle = el.element.style;
            el.newStyle = {...opt.style};
            element.style = el.newStyle;
        }

        if(opt.relFor){
            el.oldRelFor = element.__relFor;
            el.newRelFor = opt.relFor;

            element.__relFor = opt.relFor;
        }

        elements.push(el);
    }

    /**
     * 删除段落
     * @param {*} element 段落元素
     * @param {*} offset 元素偏移量
     * @param {*} notDelete 不标记删除
     * @param {*} opt 可选项
     */
    this.deleteParagraph = function(element, offset, notDelete, opt){
        deleteElement.call(this, element, offset, notDelete, opt);
    }

    /**
     * 删除换行符
     * @param {*} element 
     * @param {*} offset 
     * @param {*} notDelete 
     * @param {*} opt 可选项
     */
    this.deleteBreakline = function(element, offset, notDelete, opt){
        deleteElement.call(this, element, offset, notDelete, opt);
    }

    /**
     * 删除层
     * @param {*} element 层元素
     * @param {*} offset 元素偏移量
     * @param {*} notDelete 不标记删除
     * @param {*} opt 可选项
     */
    this.deleteLayer = function(element, offset, notDelete, opt){
        deleteElement.call(this, element, offset, notDelete, opt);
    }

    /**
     * 删除输入域
     * @param {*} element 
     * @param {*} offset 
     * @param {*} notDelete 
     * @param {*} opt 可选项
     */
    this.deleteInputArea = function(element, offset, notDelete, opt){
        deleteElement.call(this, element, offset, notDelete, opt);
    }

    /**
     * 删除表格
     * @param {*} element 表格元素
     * @param {*} offset 元素偏移量
     * @param {*} notDelete 不标记删除
     * @param {*} opt 可选项
     */
    this.deleteTable = function(element, offset, notDelete, opt){
        var offset = this.deepCloneOffset(offset);
        
        elements.push({
            element: element,
            offset: offset,
            delete: !notDelete,
            delRange: {
                startPageIndex: offset.startPageIndex,
                startRowIndex: offset.startRowIndex,
                endPageIndex: offset.endPageIndex,
                endRowIndex: offset.endRowIndex
            },
            oldParagraphIndex: element.__paragraphIndex
        });
    }

    /**
     * 删除元素(通用)
     * @param {*} element 
     * @param {*} offset 
     * @param {*} notDelete 
     * @param {*} opt 可选项
     */
    var deleteElement = function(element, offset, notDelete, opt){
        opt = opt ? opt : {};
        
        var rootOffset = this.deepCloneOffset(offset);
        var offset = this.extractDeepOffset(rootOffset);
        
        var el = {
            element: element,
            offset: rootOffset
        };

        if(!_leaveTrace){
            el.delete = !notDelete;
            el.delRange = {
                startPageIndex: offset.pageIndex,
                startRowIndex: offset.rowIndex,
                endPageIndex: offset.pageIndex,
                endRowIndex: offset.rowIndex
            };
            el.oldParagraphIndex = element.__paragraphIndex;

            if(opt.style){
                el.oldStyle = element.style;
                el.newStyle = {...element.style, ...opt.style};

                element.style = el.newStyle;
            }

            if(opt.relFor){
                el.oldRelFor = element.__relFor;
                el.newRelFor = opt.relFor;

                element.__relFor = opt.relFor;
            }
        }else{
            el.oldStyle = element.style;
            el.newStyle = {...element.style, ...opt.style, doubleDash: "middle"};
            el.offset.range = {
                start: -1,
                end: -1
            };
            element.style = el.newStyle;
            element.delete = !notDelete;
        }

        if(opt.lastElementIndex && opt.lastRowIndex == offset.rowIndex){
            opt.lastElementIndex += 1;

            this.mergeOffsetNext(el.offset, {
                elementIndex: opt.lastElementIndex
            });
        }

        if(opt.prepend){
            elements.splice(0, 0, el);
        }else{
            elements.push(el);
        }
    }
    
    /**
     * 变异文本元素，可执行多次
     * @param {*} element 文本元素
     * @param {*} offset 元素内部偏移量
     * @param {*} opt 可选项
     */
    this.mutateText = function(element, offset, opt){
        if(!_leaveTrace){
            return mutateText.call(this, element, offset);
        }else{
            return mutateTextForLeaveTrace.call(this, element, offset, opt);
        }
    }

    /**
     * 变异文本
     * @param {*} element 
     * @param {*} offset 
     * @returns 
     */
    var mutateText = function(element, offset){
        var rootOffset = this.deepCloneOffset(offset);
        var offset = this.extractDeepOffset(rootOffset);
        var contentIndex = offset.contentIndex;

        var innerText = "";
        var mutate = true;
        var range = {
            start: 0,
            end: 0
        };

        var hasPlaceholder = element.placeholder != null && element.placeholder.length > 0;
        var hasInnerText = element.innerText != null && element.innerText.length > 0;

        if(hasInnerText || (!hasInnerText && !hasPlaceholder)){
            var rowText = element.__texts[offset.pageIndex][offset.rowIndex];
            var startPageIndex = offset.pageIndex;
            var startRowIndex = offset.rowIndex;
    
            if(offset.contentIndex < 0){
                var pIndex = offset.pageIndex;
                var rIndex = offset.rowIndex - 1;
    
                if(rIndex <= 0){
                    pIndex = offset.pageIndex - 1;
    
                    if(pIndex > 0 && element.__texts[pIndex]){
                        rIndex = element.__texts[pIndex].length - 1;
    
                        if(element.__texts[pIndex][rIndex] != null){
                            rowText = element.__texts[pIndex][rIndex];
                            rowText = rowText.substr(0, rowText.length - 1);
            
                            startPageIndex = pIndex;
                            startRowIndex = rIndex;
                            contentIndex = rowText.length;
                        }
                    }
                }else if(element.__texts[pIndex][rIndex] != null){
                    rowText = element.__texts[pIndex][rIndex];
                    rowText = rowText.substr(0, rowText.length - 1);
    
                    startPageIndex = pIndex;
                    startRowIndex = rIndex;
                    contentIndex = rowText.length;
                }
            }else{
                rowText = rowText.substr(0, offset.contentIndex) + 
                    rowText.substr(offset.contentIndex + 1);
            }

            var t = null;
    
            for(var i in element.__texts){
                t = element.__texts[i];
                for(var j in t){
                    if(i < startPageIndex || (i == startPageIndex && j < startRowIndex)){
                        range.start += t[j].length;
                    }
                    innerText += i == startPageIndex && j == startRowIndex ? rowText : t[j];
                }
            }
        }

        if(hasPlaceholder && innerText.length == 0){
            contentIndex = -1;
            mutate = false;
        }

        range.start += contentIndex >= 0 ? contentIndex - 1 : contentIndex;
        range.end = range.start + 1;

        rootOffset.range = range;

        var result = {
            offset: rootOffset,
            element: element,
            oldContent: element.innerText,
            newContent: innerText,
            mutate: mutate,
            oldParagraphIndex: element.__paragraphIndex
        };

        element.innerText = innerText;

        elements.push(result);

        return this;
    }

    /**
     * 变异文本(留痕状态)
     * @param {*} element 
     * @param {*} offset 
     * @param {*} opt
     */
    var mutateTextForLeaveTrace = function(element, offset, opt){
        opt = opt ? opt : {};

        var next = this.extractDeepOffset(offset);
        this.mergeOffsetNext(offset, {
            start: next.contentIndex - 1,
            end: next.contentIndex
        });

        var splitText = this.splitText(element, [offset]);

        opt.mutateStyle = { doubleDash: "middle" };
        var result = this.composeElements(splitText, element, offset, this.wrapElement, opt);

        if(result.leftElement){
            this.mergeOffsetNext(result.leftElement.offset, {
                range: {
                    start: splitText.leftText.length - 1,
                    end: splitText.leftText.length - 1
                }
            });
            elements.push(result.leftElement);
        }

        if(result.inElement){
            result.inElement.element.delete = true;
            this.mergeOffsetNext(result.inElement.offset, {
                range: {
                    start: -1,
                    end: -1
                }
            });
            elements.push(result.inElement);
        }

        if(result.rightElement){
            elements.push(result.rightElement);
        }

        return this;
    }

    /**
     * 删除文本(deleteSelectContent使用)
     * @param {*} element 元素
     * @param {*} offsets 偏移量
     * @param {*} notDelete true 只改变内容，不标记删除
     * @param {*} opt 可选项
     */
    this.deleteText = function(element, offsets, notDelete, opt){
        if(!_leaveTrace){
            deleteText.call(this, element, offsets, notDelete, opt);
        }else{
            deleteTextForLeaveTrace.call(this, element, offsets, opt);
        }
    }

    /**
     * 删除文本元素
     * @param {*} element 文本元素
     * @param {*} offsets 元素偏移量集合
     * @param {*} notDelete true 只改变内容，不标记删除
     * @param {*} opt 可选项
     */
    var deleteText = function(element, offsets, notDelete, opt){
        var begin = this.extractDeepOffset(offsets[0]);
        var trimLeftText = "";
        var length = 0;

        //获取元素不在偏移量范围的文本(小于偏移量)
        for(var i in element.__texts){
            if(i > begin.pageIndex) break;
            
            for(var j in element.__texts[i]){
                if(i == begin.pageIndex && j > begin.rowIndex) break;

                if(i < begin.pageIndex){
                    trimLeftText += element.__texts[i][j];
                }else if(i == begin.pageIndex){
                    if(j < begin.rowIndex){
                        trimLeftText += element.__texts[i][j];
                    }else if(j == begin.rowIndex){
                        trimLeftText += element.__texts[i][j]
                            .substring(0, begin.start + 1);
                    }
                }
            }
        }

        length += trimLeftText.length;

        var offset = null;
        var inText = "";
        var text = "";

        var delStartPageIndex = null;
        var delStartRowIndex = null;
        var delEndPageIndex = null;
        var delEndRowIndex = null;

        //获取偏移量范围内的文本
        for(var i = 0; i < offsets.length; i++){
            offset = this.extractDeepOffset(offsets[i]);

            text = element.__texts[offset.pageIndex][offset.rowIndex];
            inText += text.substring(offset.start + 1, offset.end + 1);

            length += offset.end - offset.start;

            if(delStartPageIndex == null && (offset.start + 1 < text.length ||
                (offset.start < text.length && text.length == 0))){
                delStartPageIndex = offset.pageIndex;
                delStartRowIndex = offset.rowIndex;
            }

            if(offset.end > -1){
                delEndPageIndex = offset.pageIndex;
                delEndRowIndex = offset.rowIndex;
            }
        }

        //获取不在偏移量范围内文本(大于偏移量)
        var trimRightText = element.innerText.substring(length);

        var innerText = element.innerText;
        var usePlaceholder = element.innerText.length == 0 && element.placeholder != null;
        if(usePlaceholder){
            innerText = element.placeholder;
        }

        //删除标志
        var del = inText.length == innerText.length && !notDelete;
        //如果offset.end == -1, 则表示是从元素开头向上或向左选择进行删除，则该元素不可删除
        del = del && offset.end > -1;

        var el = {
            element: element,
            offset: {
                ...offsets[0]
            },
            delete: del,
            delRange: {
                startPageIndex: delStartPageIndex,
                startRowIndex: delStartRowIndex,
                endPageIndex: delEndPageIndex,
                endRowIndex: delEndRowIndex
            },
            oldParagraphIndex: element.__paragraphIndex
        };

        if(opt){
            if(opt.start){
                el.offset.range = {
                    start: trimLeftText.length - 1,
                    end: trimLeftText.length + inText.length - 1
                };
            }else if(opt.end){
                el.offset.range = {
                    start: -1,
                    end: -1
                };
            }
        }

        if(!usePlaceholder){
            el.oldContent = element.innerText;
            el.newContent = trimLeftText + trimRightText;
            element.innerText = el.newContent;
        }
        
        elements.push(el);
    }

    /**
     * 删除文本元素(留痕状态)
     * @param {*} element 文本元素
     * @param {*} offsets 元素偏移量集合
     * @param {*} opt 可选项
     */
    var deleteTextForLeaveTrace = function(element, offsets, opt){
        if(element.delete) return;

        opt = opt ? opt : {};

        var splitText = this.splitText(element, offsets);

        opt.mutateStyle = { doubleDash: "middle" };
        var result = this.composeElements(splitText, element, offsets[0], this.wrapElement, opt);
        
        if(result.leftElement){
            this.mergeOffsetNext(result.leftElement.offset, {
                range: {
                    start: splitText.leftText.length - 1,
                    end: splitText.leftText.length - 1
                }
            });
            elements.push(result.leftElement);
        }

        if(result.inElement){
            result.inElement.element.delete = true;

            this.mergeOffsetNext(result.inElement.offset, {
                range: {
                    start: -1,
                    end: -1
                }
            });
            elements.push(result.inElement);
        }

        if(result.rightElement){
            elements.push(result.rightElement);
        }

        return this;
    }

    /**
     * 获取所有元素
     * @returns 
     */
    this.getElements = function(){
        var els = [];

        for(var i in elements){
            if(elements[i].hang) continue;
            els.push(elements[i]);
        }

        return els;
    }

    /**
     * 挂载段落序号改变的元素
     * @param {*} element 元素
     * @param {*} oldParagraphIndex 旧的段落序号 
     */
    this.hang = function(element, oldParagraphIndex){
        for(var i in elements){
            if(elements[i].element === element) return;
        }

        elements.push({
            element: element,
            oldParagraphIndex: oldParagraphIndex,
            newParagraphIndex: element.__paragraphIndex,
            hang: true
        });

        return this;
    }

    /**
     * 返回当前动作的反向动作
     */
    this.reverse = function(){
        var result = {
            type: _type,
            elements: [],
            offset: null,
            insert: true,
            selectionRange: selection_ranges.reverse
        };

        var el = null;
        var elc = null;

        for(var i in elements){
            el = elements[i];
            elc = {...el};

            if(el.mutateNew){
                elc.delete = true;

                if(elc.element.__boundRect){
                    elc.delRange = this.getElementPageRange(elc.element);
                    elc.offset = {
                        pageIndex: elc.delRange.startPageIndex,
                        rowIndex: elc.delRange.startRowIndex
                    };
                }else{
                    elc.offset = this.deepCloneOffset(elc.offset);
                }

                delete elc.mutateNew;

                result.delete = true;
            }else{
                if(elc.oldContent != null){
                    elc.element.innerText = elc.oldContent;
                }
    
                if(elc.oldStyle != null){
                    elc.element.style = elc.oldStyle;
                }
    
                if(elc.element._sType != "sParagraph"){
                    if(elc.oldParagraphIndex != null){
                        el.newParagraphIndex = elc.element.__paragraphIndex;
                        elc.element.__paragraphIndex = elc.oldParagraphIndex;
                    }
                }else{
                    if(elc.oldRelFor){
                        elc.element.__relFor = elc.oldRelFor;
                    }else{
                        delete elc.element.__relFor;
                    }
                }

                if(elc.hang) continue;

                elc.offset = this.deepCloneOffset(el.offset);
    
                if(elc.offset.range){
                    elc.offset.range.start = elc.offset.range.start + 1;
                    elc.offset.range.end = elc.offset.range.end + 1;
                }
    
                if(!result.offset){
                    result.offset = elc.offset;
                }
            }

            result.elements.push(elc);
            
            this.clearMiddleProperties(elc);
        }

        return result;
    }

    /**
     * 将反向动作恢复成正向动作
     */
    this.recover = function(){
        var result = {
            type: _type,
            elements: [],
            offset: _offset,
            opt: _opt,
            selectionRange: selection_ranges.recover
        };

        var el = null;
        var elc = null;

        for(var i in elements){
            el = elements[i];
            elc = {...el};

            if(elc.hang) continue;

            if(elc.newContent != null){
                elc.element.innerText = elc.newContent;
            }

            if(elc.newStyle != null){
                elc.element.style = elc.newStyle;
            }

            if(elc.element._sType != "sParagraph"){
                if(elc.newParagraphIndex != null){
                    elc.element.__paragraphIndex = elc.newParagraphIndex;
                }
            }else{
                delete elc.element.__relFor;
            }

            elc.offset = this.deepCloneOffset(el.offset);

            result.elements.push(elc);

            this.clearMiddleProperties(elc);
        }

        return result;
    }

}